/* Animating a shark swimming
A simple shark animation using 2 images, and then making it move around screen (hopefully)
Laura Cronin
April 7, 2013
*/

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
#include <deque>
#include <algorithm>
#include <cstdlib>
#include <iostream>


using namespace std;

//screen attributes
const int SCREEN_HEIGHT = 640;
const int SCREEN_WIDTH = 1150;
const int SCREEN_BPP = 32;

//frames per second
const int FRAMES_PER_SECOND = 10;

//dimensions of shark
const int SHARK_WIDTH = 300;
const int SHARK_HEIGHT = 150;
//direction status of figure
const int SHARK_RIGHT = 0;
const int SHARK_LEFT = 1;

//fish attributes
const int FISH_WIDTH = 124;
const int FISH_HEIGHT = 56;


//surfaces
SDL_Surface *shark = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *fish = NULL;
SDL_Surface *background = NULL;

//event structure
SDL_Event event;

//areas of the sprite sheet
SDL_Rect clipsRight[3];
SDL_Rect clipsLeft[3];

class Shark{
private:
  int xoffset, yoffset;//the offset
  int dx, dy;//rate of movement
  int frame;//current frame
  int status;//animation status
public:
  Shark();//initialize variables
  void handle_events();//handles events
  void move();//move shark
  void show();//show shark
  int getStatus();
  int getXOffset();
  int getYOffset();
};

//Timer
class Timer{
private:
  int startTicks;//clock time when timer started
  int pausedTicks;///ticks stored when timer is paused
  //timer status
  bool paused;
  bool started;
public:
  Timer();
  //various clock actions
  void start();
  void stop();
  void pause();
  void unpause();
  //gets the timer's time
  int get_ticks();
  
  //checks status of timer
  bool is_started();
  bool is_paused();
};

//template <typename T>
class Fish{
private: 
  int xfish, yfish;//offset position of fish
  int fishSide;//starting side
  int dxfish;//velocity of fish
  //deque<T> FishPack;
  int current;//current fish 
public:
  Fish();
  int isEaten(Shark);//check if fish is eaten...does this need input?
  void swim();//fish moves across screen
  void showFish();//show the fish
  //void insertFromBack(T);//add new fish
  //void deleteFish();//delete current fish, like if check collision is true
  int getX();
  int getY();
  //~Fish();//deconstructor
};


SDL_Surface *load_image(std::string filename){
  //the image that's loaded
  SDL_Surface* loadedImage = NULL;
  SDL_Surface* optimizedImage = NULL;//optimized surface that will be used
  loadedImage = IMG_Load(filename.c_str());
  //if image loaded
  if(loadedImage != NULL){
    //create optimized surface
    optimizedImage = SDL_DisplayFormat(loadedImage);
    //free old surface
    SDL_FreeSurface(loadedImage);
    //if image was optimized
    if(optimizedImage != NULL){
      Uint32 colorkey = SDL_MapRGB(optimizedImage->format,255,255,255);
      SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
    }
  }
  return optimizedImage;
}


void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL){
  //hold offsets
  SDL_Rect offset;
  //get offsets
  offset.x = x;
  offset.y = y;
  //blit
  SDL_BlitSurface(source, clip, destination, &offset);
}

//will only be moving figure left and right

void set_clips(){
  //clip the sprites
  clipsRight[0].x=0;
  clipsRight[0].y=0;
  clipsRight[0].w=SHARK_WIDTH;
  clipsRight[0].h =SHARK_HEIGHT;

  clipsRight[1].x=SHARK_WIDTH;
  clipsRight[1].y = 0;
  clipsRight[1].w = SHARK_WIDTH;
  clipsRight[1].h = SHARK_HEIGHT;

  clipsRight[2].x = SHARK_WIDTH*2;
  clipsRight[2].y = 0;
  clipsRight[2].w= SHARK_WIDTH;
  clipsRight[2].h = SHARK_HEIGHT;

  clipsLeft[0].x = 0;
  clipsLeft[0].y = SHARK_HEIGHT;
  clipsLeft[0].w = SHARK_WIDTH;
  clipsLeft[0].h = SHARK_HEIGHT;

  clipsLeft[1].x = SHARK_WIDTH;
  clipsLeft[1].y = SHARK_HEIGHT;
  clipsLeft[1].w = SHARK_WIDTH;
  clipsLeft[1].h = SHARK_HEIGHT;
  
  clipsLeft[2].x = SHARK_WIDTH*2;
  clipsLeft[2].y = SHARK_HEIGHT;
  clipsLeft[2].w = SHARK_WIDTH; 
  clipsLeft[2].h = SHARK_HEIGHT;
}

bool init(){
  //initialize all SDL subsystems
  if(SDL_Init(SDL_INIT_EVERYTHING)==-1)
    return false;
  screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
  if(screen == NULL)
    return false;
  //set up window caption
  SDL_WM_SetCaption("Swimming Shark", NULL);
  //if everything initialized fine
  return true;
}

bool load_files(){
  //load shark image
  shark = load_image("SharkCombo.png");
  fish = load_image("tuna.png");
  background = load_image("ocean.png");
  //if there was a problem loading the dot
  if((shark == NULL)||(fish == NULL) || (background == NULL)){
    return false;
  }
  return true;
}

void clean_up(){
  SDL_FreeSurface(shark);
  SDL_FreeSurface(fish);
  SDL_FreeSurface(background);
  SDL_Quit();
}


Shark::Shark(){
  xoffset = 0;
  yoffset = 0;
  dx = 0;//initialize movement variables
  dy = 0;
  frame = 0;
  status= SHARK_RIGHT;//initialize animation variables
  
}

//template<typename T>
Fish::Fish(){
  fishSide = rand() % 2 + 1;//randomize this to be the left or right side of the screen
//if it is the right side of the screen, fish points left, else point right
 //x coords of fish
  if(fishSide == 1){//1 corresponds to left side 
    xfish = 0;
    dxfish = rand() % 5 +1;//test and randomize between different speeds
    }
  else{
      xfish = SCREEN_WIDTH - 300;//2 corresponds to right side
      dxfish = (rand() % 5+1) * -1 ;//neg velocity to go left
  }
  yfish = rand() % SCREEN_HEIGHT;//randomize between 0 and SCREEN_HEIGHT
    
}


int Fish::isEaten(Shark shark1){
  //check positions of shark with position of fish, this may need to be adjusted due to frame on shark size
  //if true, clear fish in main fxn
  if(shark1.getStatus() == SHARK_LEFT){
    if((shark1.getXOffset() < (xfish + FISH_WIDTH)) && (shark1.getYOffset() < (yfish + FISH_HEIGHT)) && (shark1.getXOffset() > xfish) )
      return 1;
    if((shark1.getXOffset() < xfish + FISH_WIDTH) && (shark1.getYOffset() + SHARK_HEIGHT < yfish) && (shark1.getXOffset() > xfish))
       return 1;
  }
  else if(shark1.getStatus() == SHARK_RIGHT){
    /*if(((shark1.getXOffset() + SHARK_WIDTH) > xfish) && (shark1.getYOffset() < (yfish + FISH_HEIGHT)) && (shark1.getXOffset() + SHARK_WIDTH <= xfish+FISH_WIDTH) && (shark1.getYOffset()+SHARK_HEIGHT <= (yfish + FISH_HEIGHT)))
    return 1;
       if(((shark1.getXOffset() + SHARK_WIDTH) > xfish) && ((shark1.getYOffset() + SHARK_HEIGHT) > yfish) && (shark1.getXOffset()+SHARK_WIDTH <= xfish+FISH_WIDTH) && (shark1.getYOffset()<=(yfish+FISH_HEIGHT)))
      return 1;
      }*/
    if((xfish == (shark1.getXOffset() + SHARK_WIDTH)) && ((yfish <(shark1.getYOffset()+SHARK_HEIGHT)) || ((yfish+FISH_HEIGHT)>shark1.getYOffset())))
      return 1;
  }
  
  else 
    return 0;
  
}

void Fish::swim(){

  if(dxfish < 0 ){
    xfish+=dxfish;
  }
  else
    xfish += dxfish; 
  apply_surface(xfish, yfish, fish, screen);
  
}

//template <typename T>
int Fish::getX(){
  return xfish;
}

//template <typename T>
int Fish::getY(){
  return yfish;
}



int Shark::getXOffset(){
  return xoffset;
}

int Shark::getStatus(){
  return status;
}

int Shark::getYOffset(){
  return yoffset;
}

void Shark::handle_events(){
  if(event.type == SDL_KEYDOWN){
    switch(event.key.keysym.sym){
    case SDLK_RIGHT: dx += SHARK_HEIGHT / 40; break;
    case SDLK_LEFT: dx -= SHARK_HEIGHT / 40; break;
    case SDLK_UP: dy -= SHARK_HEIGHT /40; break;
    case SDLK_DOWN: dy += SHARK_HEIGHT /40; break;
    case SDLK_ESCAPE: SDL_Quit(); break;
    }
  }
  //if key was released
  else if(event.type = SDL_KEYUP){
    //set velocity
    switch(event.key.keysym.sym){
    case SDLK_RIGHT: dx -= SHARK_HEIGHT/ 40; break;
    case SDLK_LEFT: dx += SHARK_HEIGHT/40; break;
    case SDLK_UP: dy -= SHARK_HEIGHT /40; break;
    case SDLK_DOWN: dy += SHARK_HEIGHT /40; break;
    }
  }
}
 
void Shark::move(){
  //move
  xoffset += dx;
  //keep figure in bounds
  if((xoffset < 0) || (xoffset + SHARK_WIDTH > SCREEN_WIDTH)) 
    xoffset -= dx;
  yoffset += dy;
  if((yoffset < 0)|| (yoffset + SHARK_HEIGHT > SCREEN_HEIGHT)){
    yoffset -= dy;
  }

}

void Shark::show(){
  //if moving left
  if(dx < 0){
    //set animation to the left
    status = SHARK_LEFT;
    //move to next frame in animation
    frame++;
  }
  //if moving right
  else if(dx > 0){
    status = SHARK_RIGHT;
    //move to next frame
    frame++;
  }
  //if standing
  else{
    frame = 0;//restart animation
  }
  //loop animation
  if(frame >= 3)
    frame = 0;
  //show figure
  if(status == SHARK_RIGHT){
    apply_surface(xoffset, yoffset, shark, screen, &clipsRight[frame]);
  }
  else if(status == SHARK_LEFT){
    apply_surface(xoffset, yoffset, shark, screen, &clipsLeft[frame]);
  }
}


Timer::Timer(){
  startTicks = 0;
  pausedTicks = 0;
  paused = false;
  started = false;
}

void Timer::start(){
  //start the timer
  started = true;
  paused = false;//unpause timer
}

void Timer::pause(){
  //if timer is running and isn't already paused
  if((started == true) && (paused == false)){
    paused = true;
    pausedTicks = SDL_GetTicks()-startTicks;
  }
}

void Timer::unpause(){
  //if timer is paused
  if(paused == true){
    paused = false;
    startTicks = SDL_GetTicks()-pausedTicks;//reset starting ticks
    pausedTicks = 0; //reset paused ticks
  }
}

int Timer::get_ticks(){
  //if timer is running
  if(started == true){
    //if timer is paused
    if(paused == true){
      return pausedTicks;
    }
    else{
      return SDL_GetTicks()-startTicks;
    }
  }
  return 0;
}

bool Timer::is_started(){
  return started;
}

bool Timer::is_paused(){
  return paused;
}

void Timer::stop(){
  started = false;
  paused = false;
}

int main(int argc, char* args[]){
srand(time(NULL));
  bool quit = false;
  if(init() == false) 
    return 1;
  if(load_files() == false)
    return 1;

  //sprite sheet clips
  set_clips();
  Timer fps;
  Shark testShark;
  deque<Fish> FishPack;//this needs to be a deque of fish
  int fishCount = 0;
  //while user hasn't quit
  while(quit == false){
    fps.start();//start fps timer
    //while there's events to handle
    while(SDL_PollEvent(&event)){
      testShark.handle_events();//handle events for figure
      //if user has xed out of window
      if(event.type == SDL_QUIT){
	quit = true;//quit
      }
   
    }
    cout << fps.get_ticks()<<endl;
    testShark.move();//move shark
    apply_surface(0,0,background, screen);
    //show figure on screen
    testShark.show();
    if(fps.get_ticks() % 491 == 0){//what time to use?
      Fish fish1;
      FishPack.push_back(fish1);
       fishCount++;
    }
    for(int i = 0; i<FishPack.size(); i++){

      if(FishPack[i].isEaten(testShark) == 0){

	FishPack[i].swim();
      }
      else
	FishPack.erase(FishPack.begin()+i);
      cout << " a fish deleted"<<endl;
    }
	    
    //update screen
 
    if(SDL_Flip(screen)==-1)
      return 1;
    //cap frame rate
    if(fps.get_ticks() < 1000 /FRAMES_PER_SECOND){
      SDL_Delay(( 1000 / FRAMES_PER_SECOND) - fps.get_ticks());
    }
  }
  clean_up();
  return 0;
}
